<?php

namespace Biz\Services\Site;

use Lumen\Logger\Logger;
use Illuminate\Http\Request;
use Biz\Models\Site\SitePaper;
use Illuminate\Support\Facades\DB;
use Biz\Models\Site\SitePaperAbstract;
use Biz\Criteria\Site\SiteFilterCriterion;
use Biz\Criteria\Site\PaperFilterCriterion;
use Biz\Criteria\Site\LocaleFilterCriterion;
use Lumen\Core\Exceptions\BusinessException;
use Illuminate\Contracts\Pagination\Paginator;
use Biz\Constants\Site\SitePaperAbstractConstants;
use Biz\Repositories\Site\SitePaperAbstractRepository;

/**
 * SitePaperAbstractService.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class SitePaperAbstractService
{
    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $repository;

    /**
     * @var SitePaperService
     */
    protected $paperService;

    /**
     * RepositoryController constructor.
     *
     * @param SitePaperAbstractRepository $repository
     */
    public function __construct(SitePaperAbstractRepository $repository, SitePaperService $paperService)
    {
        $this->repository              = $repository;
        $this->paperService            = $paperService;
    }

    /**
     * 列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function index(Request $request, string $paper_id): Paginator
    {
        /** @var SitePaper $paper */
        $paper    = $this->paperService->findByUid($paper_id);
        $pageSize = $request->get('page_size', 10);

        $results = $this->repository
            ->setCacheLifetime(0)
            ->pushCriterion(new PaperFilterCriterion($paper->id))
            //->pushCriterion(new LocaleFilterCriterion())
            ->paginate($pageSize);

        return $results;
    }

    /**
     * Find.
     *
     * @param int $id
     *
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function find(int $id): SitePaperAbstract
    {
        $paperAbstract = $this->repository->find($id);
        if (is_null($paperAbstract)) {
            throw new BusinessException(trans('site/paper/abstract.not_found'));
        }

        return $paperAbstract;
    }

    /**
     * Find By uid.
     *
     * @param string $uid
     *
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function findByUid(string $uid): SitePaperAbstract
    {
        $id   = SitePaperAbstract::decodeUid($uid);

        return $this->find($id);
    }

    /**
     * With find.
     *
     * @param int   $id
     * @param array $with
     *
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function findWith(int $id, $with = []): SitePaperAbstract
    {
        $paperAbstract = $this->repository->with($with)->find($id);
        if (is_null($paperAbstract)) {
            throw new BusinessException(trans('site/paper/abstract.not_found'));
        }

        return $paperAbstract;
    }

    /**
     * Find By Site Id.
     *
     * @param int $paper_id
     *
     * @throws BusinessException
     *
     * @return bool
     */
    public function findBySiteId(int $paper_id)
    {
        $paperAbstract = $this->repository
            ->pushCriterion(new SiteFilterCriterion($paper_id))
            ->findFirst();

        return $paperAbstract;
    }

    /**
     * Check By Paper Id.
     *
     * @param int $paper_id
     *
     * @throws BusinessException
     *
     * @return void
     */
    public function checkByPaperId(int $paper_id): void
    {
        $paper = $this->repository->setCacheLifetime(0)->pushCriterion(new PaperFilterCriterion($paper_id))->findFirst();
        if ($paper) {
            throw new BusinessException(trans('site/paper/abstract.paper_has_already_existed'));
        }
    }

    /**
     * Check By Paper And Abstract.
     *
     * @param SitePaper         $paper
     * @param SitePaperAbstract $paperAbstract
     *
     * @throws BusinessException
     */
    public function checkByPaperAndAbstract(SitePaper $paper, SitePaperAbstract $paperAbstract): void
    {
        if ($paper->id !== $paperAbstract->paper_id) {
            throw new BusinessException(trans('site/paper/abstract.not_found'));
        }
    }

    /**
     * store.
     *
     * @param Request $request
     * @param string  $paper_id
     *
     * @throws \Exception
     *
     * @return SitePaperAbstract
     */
    public function store(Request $request, string $paper_id): SitePaperAbstract
    {
        $data = $request->all();
        /** @var SitePaper $paper */
        $paper = $this->paperService->findByUid($paper_id);

        $data['paper_id'] = $paper->id;

        return $this->create($data);
    }

    /**
     * Create.
     *
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SitePaperAbstract
     */
    public function create(array $data): SitePaperAbstract
    {
        // Check Paper ID
        $paper_id = $data['paper_id'];
        $this->checkByPaperId($paper_id);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // 创建摘要
            $data['status'] = SitePaperAbstractConstants::STATUS_SUBMISSION;

            $paperAbstract   = $this->repository->create($data);
            if (! $paperAbstract) {
                throw new BusinessException(trans('site/paper/abstract.create_fail'));
            }

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $paperAbstract;
    }

    /**
     * Detail.
     *
     * @param string $paper_id
     * @param string $abstract_id
     *
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function show(string $paper_id, string $abstract_id): SitePaperAbstract
    {
        /** @var SitePaperAbstract $paperAbstract */
        $paperAbstract = $this->findByUid($abstract_id);

        /** @var SitePaper $paper */
        $paper = $this->paperService->findByUid($paper_id);

        $this->checkByPaperAndAbstract($paper, $paperAbstract);

        return $paperAbstract;
    }

    /**
     * Edit.
     *
     * @param string $paper_id
     * @param string $abstract_id
     * @param array  $data
     *
     * @throws \Exception
     *
     * @return SitePaperAbstract
     */
    public function edit(string $paper_id, string $abstract_id, array $data): SitePaperAbstract
    {
        $id               = SitePaperAbstract::decodeUid($abstract_id);
        $data['paper_id'] = $paper_id;

        return $this->update($id, $data);
    }

    /**
     * Update.
     *
     * @param int   $id
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SitePaperAbstract
     */
    public function update(int $id, array $data): SitePaperAbstract
    {
        $paperAbstract = $this->find($id);

        /** @var SitePaper $paper */
        $paper_id         = $data['paper_id'];
        $paper            = $this->paperService->findByUid($paper_id);
        $data['paper_id'] = $paper->id;

        $this->checkByPaperAndAbstract($paper, $paperAbstract);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $data['status']  = SitePaperAbstractConstants::STATUS_SUBMISSION;
            $paperAbstract   = $this->repository->update($paperAbstract, $data);
            if (! $paperAbstract) {
                throw new BusinessException(trans('site/paper/abstract.create_fail'));
            }

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $paperAbstract;
    }

    /**
     * Remove.
     *
     * @param string $paper_id
     * @param string $abstract_id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function remove(string $paper_id, string $abstract_id): bool
    {
        $id   = SitePaperAbstract::decodeUid($abstract_id);

        return $this->delete($paper_id, $id);
    }

    /**
     * Delete.
     *
     * @param string $paper_id
     * @param int    $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function delete(string $paper_id, int $id): bool
    {
        /** @var SitePaperAbstract $paperAbstract */
        $paperAbstract = $this->find($id);

        /** @var SitePaper $paper */
        $paper = $this->paperService->findByUid($paper_id);

        $this->checkByPaperAndAbstract($paper, $paperAbstract);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $this->repository->delete($paperAbstract);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return true;
    }

    /**
     * Must Submission Status.
     *
     * @param SitePaperAbstract $abstract
     *
     * @throws BusinessException
     *
     * @return void
     */
    public function mustStatusSubmission(SitePaperAbstract $abstract): void
    {
        if (SitePaperAbstractConstants::STATUS_SUBMISSION !== $abstract->status) {
            throw new BusinessException(trans('site/paper/abstract.must_status_submission'));
        }
    }

    /**
     * Must Review Status.
     *
     * @param SitePaperAbstract $abstract
     *
     * @throws BusinessException
     *
     * @return void
     */
    public function mustStatusReview(SitePaperAbstract $abstract): void
    {
        if (SitePaperAbstractConstants::STATUS_REVIEW !== $abstract->status) {
            throw new BusinessException(trans('site/paper/abstract.must_status_review'));
        }
    }

    /**
     * Review.
     *
     * @param string $paper_id
     * @param string $abstract_id
     *
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function review(string $paper_id, string $abstract_id): SitePaperAbstract
    {
        /** @var SitePaperAbstract $paperAbstract */
        $paperAbstract = $this->findByUid($abstract_id);

        /** @var SitePaper $paper */
        $paper = $this->paperService->findByUid($paper_id);

        $this->checkByPaperAndAbstract($paper, $paperAbstract);

        $this->paperService->mustStatusAbstract($paper);

        $this->mustStatusSubmission($paperAbstract);

        // Update Status
        $data['status']  = SitePaperAbstractConstants::STATUS_REVIEW;
        $paperAbstract   = $this->repository->update($paperAbstract, $data);

        return $paperAbstract;
    }

    /**
     * Passed.
     *
     * @param string $paper_id
     * @param string $abstract_id
     *
     * @throws \Exception
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function passed(string $paper_id, string $abstract_id): SitePaperAbstract
    {
        /** @var SitePaperAbstract $paperAbstract */
        $paperAbstract = $this->findByUid($abstract_id);

        /** @var SitePaper $paper */
        $paper = $this->paperService->findByUid($paper_id);

        $this->checkByPaperAndAbstract($paper, $paperAbstract);

        $this->paperService->mustStatusAbstract($paper);

        $this->mustStatusReview($paperAbstract);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // Update Status
            $data['status']  = SitePaperAbstractConstants::STATUS_PASSED;
            $paperAbstract   = $this->repository->update($paperAbstract, $data);

            $this->paperService->updateStatusFull($paper);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $paperAbstract;
    }

    /**
     * Refuse.
     *
     * @param string $paper_id
     * @param string $abstract_id
     *
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function refuse(string $paper_id, string $abstract_id): SitePaperAbstract
    {
        /** @var SitePaperAbstract $paperAbstract */
        $paperAbstract = $this->findByUid($abstract_id);

        /** @var SitePaper $paper */
        $paper = $this->paperService->findByUid($paper_id);

        $this->checkByPaperAndAbstract($paper, $paperAbstract);

        $this->paperService->mustStatusAbstract($paper);

        $this->mustStatusReview($paperAbstract);

        // Update Status
        $data['status']  = SitePaperAbstractConstants::STATUS_REVIEW;
        $paperAbstract   = $this->repository->update($paperAbstract, $data);

        return $paperAbstract;
    }

    /**
     * Revise.
     *
     * @param string $paper_id
     * @param string $abstract_id
     *
     * @throws BusinessException
     *
     * @return SitePaperAbstract
     */
    public function revise(string $paper_id, string $abstract_id): SitePaperAbstract
    {
        /** @var SitePaperAbstract $paperAbstract */
        $paperAbstract = $this->findByUid($abstract_id);

        /** @var SitePaper $paper */
        $paper = $this->paperService->findByUid($paper_id);

        $this->checkByPaperAndAbstract($paper, $paperAbstract);

        $this->paperService->mustStatusAbstract($paper);

        $this->mustStatusReview($paperAbstract);

        // Update Status
        $data['status']  = SitePaperAbstractConstants::STATUS_REVISE;
        $paperAbstract   = $this->repository->update($paperAbstract, $data);

        return $paperAbstract;
    }
}
